home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Format 1995 June
/
MacFormat 25.iso
/
Shareware City
/
Developers
/
GetFileIcon ƒ
/
GetFileIcon.c
next >
Wrap
Text File
|
1995-01-02
|
14KB
|
608 lines
/*
GetFileIcon.c
1/2/95
ver 1.0
-------
GetFileIcon is based on the FindIcon.c code by James Walker.
Q: Why does GetFileIcon exist? Why not use FindIcon?
A: There are several reasons:
1. Displaying a file's icon is one of the most intuitive things to do on a
a Macintosh. Unfortunately, it is also very difficult; I would estimate
that there is at least one person a week on the comp.sys.mac.programmer
newsgroup who asks how to display the icon of a file. Most programmers
are usually referred to the FindIcon code by James Walker, but the code only
shows how to get a files' icon; it doesn’t demonstrate how to display the
icon. Several programmers have posted messages requesting further help...
this snippet is intended to take care of that need.
2. The FindIcon routines are able to get a file or a folders' icon.
Personally, I do not need to retrieve a folders' icon, so I took everything
that pertained to folders out (thus, reducing the amount of code by
approximately half).
3. The FindIcon routine is comprised of 13 source files and 14 header files.
With GetFileIcon, there are only two files to keep track of (GetFileIcon.c
and GetFileIcon.h).
4. When I compile my project, I always have strict type checking turned on.
Since GetFileIcon uses forbid_action() and forbid() in conjunction with
'gotos', it took quite a bit of tweaking on my part to get the code to work.
Q: How do I use GetFileIcon?
A: Simple, In your THINK C project, make sure you have MacTraps and MacTraps2
added, then add GetFileIcon.c to the project. For an example on how to call
GetFileIcon, look in GetFileIconExample.c. BTW: This code seems to compile
fine under THINK C 6.0 -> 7.0.4... I do not know about earlier versions of
THINK C.
Other useful information: If you wish to contact me, my Internet address is
jbeeghly@u.washington.edu (at least it is until June '95). I make no guarantees
over the stability of the code (in other words, use it at your own risk). If
you want to find out more about getting & plotting a files' icon, I strongly suggest
you get the code to FindIcon (available at most mac development FTP sites) and THINK
Reference.
*/
#include "GetFileIcon.h"
/* ------------------------------------------------------------------
GetFileIcon Given a file specification for a file, folder, or
volume, create an appropriate icon suite
and find its label color.
------------------------------------------------------------------ */
pascal OSErr GetFileIcon(
/* --> */ FSSpec *thing,
/* --> */ IconSelectorValue iconSelector,
/* <-- */ Handle *theSuite)
{
CInfoPBRec cpb;
OSErr err;
*theSuite = NULL;
if( IsVolEjected(thing->vRefNum) )
{
err = volOffLinErr;
}
else
{
cpb.hFileInfo.ioVRefNum = thing->vRefNum;
cpb.hFileInfo.ioDirID = thing->parID;
cpb.hFileInfo.ioNamePtr = thing->name;
cpb.hFileInfo.ioFDirIndex = 0;
err = PBGetCatInfoSync( &cpb );
if( !err )
{
if( (cpb.hFileInfo.ioFlAttrib & ioDirMask) == 0) // file
{
if(cpb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon)
{
err = GetCustomFileIcon(thing, iconSelector, theSuite );
}
else // no custom icon
{
err = GetNormalFileIcon(&cpb, iconSelector, theSuite);
}
}
// ----------- end of normal case --------------
}
}
// ------- error handler ---------
/*if(thing->parID == fsRtParID) // a volume
{
if(err == volOffLinErr)
{
*labelColor = ttOffline;
}
err = GetVolumeIcon(thing->vRefNum, iconSelector, theSuite);
}*/
return( err );
}
Boolean IsVolEjected( short vRefNum )
{
OSErr err;
HVolumeParam vol_pb;
vol_pb.ioNamePtr = NULL;
vol_pb.ioVRefNum = vRefNum;
vol_pb.ioVolIndex = 0;
err = PBHGetVInfoSync( (HParmBlkPtr )&vol_pb );
return( (err == noErr) && (vol_pb.ioVDRefNum > 0) );
}
OSErr GetCustomFileIcon(
/* --> */ FSSpec *filespec,
/* --> */ IconSelectorValue iconSelector,
/* <-- */ Handle *theSuite)
{
short saveResFile, customResFile;
OSErr err;
saveResFile = CurResFile();
SetResLoad( false );
customResFile = FSpOpenResFile(filespec, fsRdPerm);
SetResLoad( true );
if(customResFile == -1)
{
err = ResError();
}
else
{
err = GetResourceIcons(theSuite, kCustomIconResource, iconSelector);
if( !err )
{
if( IsSuiteEmpty( *theSuite ) )
{
err = GetResourceIcons(theSuite, kVolumeAliasIconResource, iconSelector);
}
}
CloseResFile( customResFile );
UseResFile( saveResFile );
}
return( err );
}
OSErr GetNormalFileIcon(
/* --> */ CInfoPBRec *cpb,
/* --> */ IconSelectorValue iconSelector,
/* <-- */ Handle *theSuite)
{
OSErr err;
long dataSize;
Handle iconData;
Byte iconType;
GetIconData getData;
short iconID;
Boolean inFinder;
short saveResFile, FinderResFile, sysVRefNum;
long sysDirID;
iconID = FindGenericIconID(cpb->hFileInfo.ioFlFndrInfo.fdType, &inFinder );
saveResFile = CurResFile();
if( inFinder )
{
//(void) FindFolder( kOnSystemDisk, kSystemFolderType,
// kDontCreateFolder, &sys_vRefNum, &sys_dirID );
FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, &sysVRefNum, &sysDirID);
SetResLoad( false );
FinderResFile = HOpenResFile(sysVRefNum, sysDirID, "\pFinder", fsRdPerm);
SetResLoad( true );
if(FinderResFile == -1)
{
err = ResError();
}
else
{
err = GetResourceIcons(theSuite, iconID, iconSelector);
CloseResFile( FinderResFile );
}
}
else // icons in desktop DB or in System
{
getData.DTRefNum = FindDesktopDatabase(cpb->dirInfo.ioVRefNum,
cpb->hFileInfo.ioFlFndrInfo.fdCreator );
if(getData.DTRefNum != 0) // the right icons are in some desktop
{
err = NewIconSuite( theSuite );
if( !err )
{
getData.fileCreator = cpb->hFileInfo.ioFlFndrInfo.fdCreator;
getData.fileType = cpb->hFileInfo.ioFlFndrInfo.fdType;
if(getData.fileType == kApplicationAliasType)
{
getData.fileType = 'APPL';
}
err = ForEachIconDo(*theSuite, iconSelector, GetIconProc, &getData);
}
}
if( (getData.DTRefNum == 0) || IsSuiteEmpty( *theSuite ) )
{
UseResFile( 0 );
err = GetResourceIcons(theSuite, iconID, iconSelector);
}
}
UseResFile( saveResFile );
return( err );
}
/* ------------------------------------------------------------------
GetIcon This is an IconAction procedure to fill in one
slot of an icon suite, given a file type, creator,
and desktop database.
------------------------------------------------------------------ */
static pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr)
{
OSErr err;
GetIconData *data;
DTPBRec deskRec;
err = noErr;
data = (GetIconData *)yourDataPtr;
*theIcon = NewHandle( kLarge8BitIconSize );
//require_action( *theIcon, NewHandle, err = memFullErr );
if( !(*theIcon) )
{
err = memFullErr;
}
else
{
HLock( *theIcon );
deskRec.ioDTRefNum = data->DTRefNum;
deskRec.ioDTBuffer = **theIcon;
deskRec.ioDTReqCount = kLarge8BitIconSize;
deskRec.ioFileCreator = data->fileCreator;
deskRec.ioFileType = data->fileType;
switch( theType )
{
case large1BitMask:
deskRec.ioIconType = kLargeIcon;
break;
case large4BitData:
deskRec.ioIconType = kLarge4BitIcon;
break;
case large8BitData:
deskRec.ioIconType = kLarge8BitIcon;
break;
case small1BitMask:
deskRec.ioIconType = kSmallIcon;
break;
case small4BitData:
deskRec.ioIconType = kSmall4BitIcon;
break;
case small8BitData:
deskRec.ioIconType = kSmall8BitIcon;
break;
default:
// The desktop database does not have "mini" icons
deskRec.ioIconType = 1000;
break;
}
err = PBDTGetIconSync( &deskRec );
if(err == noErr)
{
HUnlock( *theIcon );
SetHandleSize(*theIcon, deskRec.ioDTActCount);
}
else
{
DisposeHandle( *theIcon );
*theIcon = NULL;
err = noErr;
}
}
return( err );
}
/* ------------------------------------------------------------------
Find_desktop_database Find the reference number of a
desktop database containing icons
for a specified creator code.
The search begins on a specified volume, but covers all volumes.
------------------------------------------------------------------ */
static short FindDesktopDatabase(
/* --> */ short firstVRefNum,
/* --> */ OSType fileCreator) // returns a DT refnum or 0
{
OSErr err;
VolumeParam vpb;
short DTRefNum;
DTRefNum = 0;
if(!InOneDesktop(firstVRefNum, fileCreator, &DTRefNum))
{
vpb.ioNamePtr = NULL;
for(vpb.ioVolIndex = 1; PBGetVInfoSync((ParmBlkPtr )&vpb) == noErr; ++vpb.ioVolIndex)
{
if(vpb.ioVRefNum == firstVRefNum)
continue;
if( InOneDesktop(vpb.ioVRefNum, fileCreator, &DTRefNum) )
break;
}
}
return( DTRefNum );
}
/* ------------------------------------------------------------------
InOneDesktop Determine whether the desktop database for
one particular volume contains icons for
a given creator code, and if so, return its
reference number.
------------------------------------------------------------------
*/
static Boolean InOneDesktop(
/* --> */ short vRefNum,
/* --> */ OSType fileCreator,
/* <-- */ short *dtRefNum)
{
OSErr err;
DTPBRec deskRec;
Boolean retVal;
retVal = false; // default to failure
deskRec.ioNamePtr = NULL;
deskRec.ioVRefNum = vRefNum;
err = PBDTGetPath( &deskRec );
if( !err )
{
/* We want to ignore any non-icon data, such as the 'paul'
item that is used for drag-and-drop. */
deskRec.ioFileCreator = fileCreator;
deskRec.ioIndex = 1;
do
{
deskRec.ioTagInfo = 0;
err = PBDTGetIconInfoSync( &deskRec );
deskRec.ioIndex += 1;
}while( (err == noErr) && (deskRec.ioIconType <= 0) );
if(err == noErr)
{
retVal = true;
*dtRefNum = deskRec.ioDTRefNum;
}
}
return( retVal );
}
pascal OSErr GetResourceIcons(
/* <-- */ Handle *theSuite,
/* --> */ short theID,
/* --> */ long theSelector)
{
OSErr err;
err = Get1IconSuite(theSuite, theID, theSelector);
if(err == noErr)
{
err = CopyEachIcon( *theSuite );
}
return( err );
}
OSErr CopyEachIcon(
/* <-> */ Handle theSuite)
{
return( ForEachIconDo(theSuite, svAllAvailableData, CopyOneIcon, NULL) );
}
static pascal OSErr CopyOneIcon(
/* --> */ ResType theType,
/* <-> */ Handle *theIcon,
/* --- */ void *yourDataPtr)
{
OSErr err;
if(*theIcon != NULL)
{
LoadResource( *theIcon );
err = HandToHand( theIcon );
if(err != noErr)
*theIcon = NULL;
}
return( noErr );
}
short FindGenericIconID(
/* --> */ OSType theType,
/* <-- */ Boolean *inFinder)
{
short id;
register OSType *iconTypes;
register short *iconIDs;
Ptr iconIDsStart;
OSType *beginSysIcons;
asm {
BRA @start
@icon_type_storage
dc.L 'ifil'
dc.L 'sfil'
dc.L 'ffil'
dc.L 'tfil'
dc.L 'kfil'
dc.L 'FFIL'
dc.L 'DFIL'
@Finder_icons_end
dc.L kContainerFolderAliasType
dc.L kContainerTrashAliasType
dc.L kSystemFolderAliasType
dc.L 'INIT'
dc.L 'APPL'
dc.L 'dfil'
dc.L 'pref'
dc.L kAppleMenuFolderAliasType
dc.L kControlPanelFolderAliasType
dc.L kExtensionFolderAliasType
dc.L kPreferencesFolderAliasType
dc.L kStartupFolderAliasType
dc.L kApplicationAliasType
dc.L kExportedFolderAliasType
dc.L kDropFolderAliasType
dc.L kSharedFolderAliasType
dc.L kMountedFolderAliasType
@icon_id_storage
dc.W 12500
dc.W 14000
dc.W 14500
dc.W 14501
dc.W 14750
dc.W 15500
dc.W 15750
dc.W genericFolderIconResource
dc.W trashIconResource
dc.W systemFolderIconResource
dc.W genericExtensionIconResource
dc.W genericApplicationIconResource
dc.W genericDeskAccessoryIconResource
dc.W genericPreferencesIconResource
dc.W appleMenuFolderIconResource
dc.W controlPanelFolderIconResource
dc.W extensionsFolderIconResource
dc.W preferencesFolderIconResource
dc.W startupFolderIconResource
dc.W genericApplicationIconResource
dc.W ownedFolderIconResource
dc.W dropFolderIconResource
dc.W sharedFolderIconResource
dc.W mountedFolderIconResource
@start
LEA @icon_type_storage, iconTypes
LEA @icon_id_storage, iconIDs
LEA @Finder_icons_end, A0
move.L A0, beginSysIcons
}
iconIDsStart = (Ptr )iconIDs;
id = genericDocumentIconResource; // default
while( ((Ptr )iconTypes) < iconIDsStart)
{
if(theType == *iconTypes)
{
id = *iconIDs;
break;
}
iconTypes++;
iconIDs++;
}
*inFinder = (iconTypes < beginSysIcons);
return( id );
}
/* --------------------------------------------------------------------
Get1IconSuite Like GetIconSuite, but only looks in
the current resource file.
In case you're wondering why it would be necessary to ensure that
icons come from only one file, suppose you're looking at a
file that has its custom icon bit set, but for some reason does
not contain a custom icon, or at least not a full family.
Way down the resource chain, there may be another file, say a
font file, that does have a full family of custom icons.
So you get an unexpected icon.
-------------------------------------------------------------------- */
pascal OSErr Get1IconSuite(
/* <-- */ Handle *theSuite,
/* --> */ short theID,
/* --> */ long theSelector)
{
OSErr err;
err = NewIconSuite( theSuite );
if( !err )
{
err = ForEachIconDo(*theSuite, theSelector,
(IconAction ) Get1Icon, &theID);
}
return( err );
}
static pascal OSErr Get1Icon(
/* --> */ ResType theType,
/* <-> */ Handle *theIcon,
/* --> */ short *resID)
{
*theIcon = Get1Resource(theType, *resID);
return( noErr );
}
static pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr)
{
if(*theIcon != NULL)
*(Boolean *)yourDataPtr = false; // not empty!
return( noErr );
}
Boolean IsSuiteEmpty( Handle theSuite )
{
Boolean retVal;
retVal = true;
ForEachIconDo(theSuite, svAllAvailableData, TestHandle, &retVal);
return( retVal );
}